//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _APPS_BUSH_BUILTINS_CCDBUILTIN_H_
#define _APPS_BUSH_BUILTINS_CCDBUILTIN_H_

#include "../cbuiltin.h"
#include <buola/io/curi.h>
#include <buola/os/cenv.h>
#include "../cinterpreter.h"
#include <buola/algorithm/split.h>
#include <buola/tty/output.h>

namespace buola { namespace bush {

struct CCdBuiltin : public CBuiltin
{
    void PrintUsage()
    {
        msg_error() << "wrong parameters\n";
        msg_info() << "usage: cd [path | -[n] | -l]\n";
    }
    
    virtual int Run(const std::vector<std::string> &pArgs,io::PBufferStream pOS)
    {
        io::CTextWriter lW(pOS);
        if(pArgs.size()>1)
        {
            PrintUsage();
            return -1;
        }
        
        io::CURI lPath;
        std::vector<io::CURI> &lCDStack=gInterpreter->GetCDStack();
        if(pArgs.empty())
        {
            lPath=io::get_home();
        }
        else if(pArgs[0][0]=='-')
        {
            if(pArgs[0]=="-l")
            {
                for(int i=lCDStack.size()-1;i>=1;i--)
                {
                    lW << i << " - " << tty::color(tty::COLOR_BRIGHTBLUE,lCDStack[i].Path()) << "\n";
                }
                return 0;
            }
            int lNum=1;
            if(pArgs[0].length()>1)
            {
                lNum=to_<int>(pArgs[0].substr(1));
            }
            
            if(lNum<1||lNum>=lCDStack.size())
            {
                msg_error() << "wrong index in CD stack\n";
                return -1;
            }
            
            lPath=lCDStack[lNum];
            lCDStack.erase(lCDStack.begin()+lNum);
        }
        else
        {
            ///\todo use path manipulation functions in io
            std::vector<std::string> lComponents;
            if(pArgs[0][0]=='/')
            {
                split(pArgs[0],lComponents,fn::equal_to('/'),nDeleteEmpty);
            }
            else
            {
                split(lCDStack.front().Path(),lComponents,fn::equal_to('/'),nDeleteEmpty);
                std::vector<std::string> lNewComponents;
                split(pArgs[0],lNewComponents,fn::equal_to('/'),nDeleteEmpty);
                lComponents.insert(lComponents.end(),lNewComponents.begin(),lNewComponents.end());
            }
            
            std::vector<std::string> lFinal;
            for(int i=0;i<lComponents.size();i++)
            {
                if(lComponents[i]=="."||lComponents[i].empty())
                    continue;
                else if(lComponents[i]=="..")
                {
                    if(lFinal.size())
                        lFinal.pop_back();
                    continue;
                }
                
                lFinal.push_back(lComponents[i]);
            }
            
            lPath=io::file(lFinal);
        }
        
        ///\todo change it to some function in io namespace which actually takes a URI
        if(chdir(lPath.Path().c_str())!=0)
        {
            msg_error() << "can't change directory\n";
            return -1;
        }
    
        CEnv::Set("PWD",lPath.Path());
        for(int i=0;i<lCDStack.size();i++)
        {
            if(lCDStack[i]==lPath)
            {
                lCDStack.erase(lCDStack.begin()+i);
                break;
            }
        }
        
        lCDStack.insert(lCDStack.begin(),lPath);
        
        if(lCDStack.size()>26)
            lCDStack.resize(26);
        
        return 0;
    }

    virtual std::wstring GetDescription()   {   return L"change directory";    }
};

/*namespace bush*/ } /*namespace buola*/ }

#endif
